/*
 * PyPair.h
 *
 *  Created on: Dec 28, 2011
 *      Author: allan
 */

#ifndef PYPAIR_H_
#define PYPAIR_H_

// C++ includes
#include <string>
#include <utility>

// Boost includes
#include <boost/python.hpp>
using namespace boost::python;

template<typename T, typename U>
struct std_pair_to_python_tuple
{
	static PyObject* convert(const std::pair<T,U>& p)
	{
		tuple t = make_tuple(p.first, p.second);
		
		return incref(t.ptr());
	}
};

template<typename T, typename U>
struct std_pair_from_python_tuple
{
	std_pair_from_python_tuple()
	{
		converter::registry::push_back(
			&convertible, &construct, type_id<std::pair<T,U>>());
	}

	static void* convertible(PyObject* obj_ptr)
	{
		if(!PyTuple_Check(obj_ptr))
			return 0;
		return obj_ptr;
	}

	static void construct(
		PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
	{
		extract<tuple> x(obj_ptr);
		if(!x.check())
			throw_error_already_set();
		
		tuple t = x();

		void* storage = 
			((converter::rvalue_from_python_storage<std::pair<T,U>>*) data)->
				storage.bytes;
		
		new (storage) std::pair<T,U>();

		std::pair<T,U>& p = *reinterpret_cast<std::pair<T,U>*>(storage);
		
		p.first  = extract<T>(t[0]);
		p.second = extract<U>(t[1]);

		data->convertible = storage;
	}
};

template<typename T, typename U>
void init_converter_std_pair_from_python_tuple()
{
	//to_python_converter<std::pair<T,U>, std_pair_to_python_tuple<T,U>>();
	
	std_pair_from_python_tuple<T,U>();
}

// Reference: http://mail.python.org/pipermail/cplusplus-sig/2006-May/010346.html
namespace std
{
	template<typename T, typename U>
	std::ostream& operator<<(std::ostream& out, const std::pair<T,U>& pair)
	{
		out << "(" << pair.first << ", " << pair.second << ")";
	
		return out; 
	}
}

template<typename T, typename U>
void export_std_pair(const char* type_name)
{
	init_converter_std_pair_from_python_tuple<T,U>();
	
	class_<std::pair<T,U>>(type_name)
		.def_readwrite("fst", &std::pair<T,U>::first)
		.def_readwrite("snd", &std::pair<T,U>::second)
		.def(self_ns::str(self_ns::self));
}

#endif /* PYPAIR_H_ */
